package DAO;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import Pojo.Aluno;
import Pojo.HistoricoTurma;
import Pojo.Nota;
import Pojo.Atividade;

/** Classe NotaDao
 * Essa classe implementa a interface NotaDao para comunicar com arquivo.
 * @author Maione José
 *
 */
public class NotaDaoImplArquivo implements NotaDao {
	
	/** Lista de Notas.*/
	private List<Nota> listaNotas;
	
	/** Atributo constante com o endereço do arquivo onde será armazenada os dados.*/
	private static final String nomeArquivo = "Arquivos/Notas.txt";
	
	/** Atributo onde é guardado o próximo id para inserção na lista.*/
	private int proximoId;
	
	/**
	 * Construtor da classe que busca dados no arquivo
	 */
	public NotaDaoImplArquivo(){
		this.listaNotas = new ArrayList<Nota>();
		this.proximoId=0;
		this.buscarArmazenamento();
	}
	
	/**
	 * Getter do próximo id da Nota
	 * @return próximo id disponível
	 */
	public int getProximoId(){
		return(this.proximoId);
	}
	
	/**
	 * Lista de Notas. 
	 * @return Lista das Notas.
	 */
	public List<Nota> getListaNotas(){
		return(this.listaNotas);
	}
	
	/**
	 * Busca Armazenamento no arquivo, trata os dados e monta a lista das notas.
	 */
	private void buscarArmazenamento(){
		try{
			this.listaNotas = new ArrayList<Nota>();
			FileReader arq = new FileReader(nomeArquivo);		//Cria objeto arquivo
		    BufferedReader lerArq = new BufferedReader(arq);	//Cria objeto de leitura
		    String linha=lerArq.readLine();
		    Nota nota;
		    String dados[];
		    Aluno aluno;
		    Atividade atividade;
		    
		    while (linha != null) {
		    	dados = linha.split("\t");
		    	aluno = buscarAluno(Integer.parseInt(dados[2]));
		    	atividade = buscarAtividade(Integer.parseInt(dados[3]));
		    	nota = new Nota(Integer.parseInt(dados[0]),Double.parseDouble(dados[1]),aluno, atividade);
		    	this.listaNotas.add(nota);
		    	linha = lerArq.readLine();						//Lê as linhas.
		    	this.proximoId=Integer.parseInt(dados[0]);
		    }
		    this.proximoId++;
		    
		    arq.close();										//Fechando o arquivo
		}catch (IOException e) {
			System.err.printf("Erro ao manipular o arquivo: %s.\n",e.getMessage());
		}
	}
	
	/**
	 * Busca no armazenamento usando o id de um aluno. É usado para quando não se quer carregar os dados para a lista.
	 * @param idAluno
	 * @return Lista de Notas
	 */
	public List<Nota> buscarArmazenamentoProcurarPorAluno(int idAluno){
		try{
			FileReader arq = new FileReader(nomeArquivo);		//Cria objeto arquivo
		    BufferedReader lerArq = new BufferedReader(arq);	//Cria objeto de leitura
		    String linha=lerArq.readLine();
		    String dados[];
		    Nota nota;
		    List<Nota> listaNota = new ArrayList<Nota>();
		    
		    while (linha != null) {
		    	dados = linha.split("\t");
		    	if (Integer.parseInt(dados[2])==idAluno){
		    		nota = new Nota(Integer.parseInt(dados[0]),Double.parseDouble(dados[1]));
		    		listaNota.add(nota);
		    	}
		    	linha = lerArq.readLine();						//Lê as linhas.
		    }
		    arq.close();										//Fechando o arquivo
		    return(listaNota);
		}catch (IOException e) {
			System.err.printf("Erro ao manipular o arquivo: %s.\n",e.getMessage());
		}
		return(null);
	}
	
	/**
	 * Busca no armazenamento usando o id de um atividade. É usado para quando não se quer carregar os dados para a lista.
	 * @param idAtividade
	 * @return Lista de Notas
	 */
	public List<Nota> buscarArmazenamentoPorAtividade(int idAtividade){
		List<Nota> ListaNotas = new ArrayList<Nota>();
		
		try{
			FileReader arq = new FileReader(nomeArquivo);		//Cria objeto arquivo
		    BufferedReader lerArq = new BufferedReader(arq);	//Cria objeto de leitura
		    String linha=lerArq.readLine();
		    String dados[];
		    Nota nota;
		    List<Nota> listaNota = new ArrayList<Nota>();
		    
		    while (linha != null) {
		    	dados = linha.split("\t");
		    	if (Integer.parseInt(dados[2])==idAtividade){
		    		nota = new Nota(Integer.parseInt(dados[0]),Double.parseDouble(dados[1]));
		    		listaNota.add(nota);
		    	}
		    	linha = lerArq.readLine();						//Lê as linhas.
		    }
		    arq.close();										//Fechando o arquivo
		    return(listaNota);
		}catch (IOException e) {
			System.err.printf("Erro ao manipular o arquivo: %s.\n",e.getMessage());
		}
		return(null);
	}
	
	/**
	 * Método usado para salvar a lista do arquivo. O arquivo é sobrescrito nesse método.
	 */
	private void salvarArmazenamento(){
		try {
			BufferedWriter out = new BufferedWriter(new FileWriter(nomeArquivo));
			Iterator<Nota> i = listaNotas.iterator();
			
			Nota nota;
			while(i.hasNext()){
				nota = (Nota) i.next();
				out.write(nota.toString());
			}
			
			out.close();
		} catch (IOException e) {
			System.err.printf("Erro ao manipular o arquivo: %s.\n",e.getMessage());
		}
	}
	
	/**
	 * Método de adicionar a Nota na lista. 
	 * É verificado se ele o código já existe, pois se existir não pode ser adicionado.
	 * Após inserir, o método "salvarArmazenamento()" é chamado
	 * @param nota
	 * @return true se foi possível inserir ou falso se ele foi encontrado na lista.
	 */
	public boolean adicionarNota(Nota nota){
		Iterator<Nota> i = listaNotas.iterator();
		Nota notaComparacao;
		while(i.hasNext()){
			notaComparacao = (Nota) i.next();
			if (notaComparacao.getIdNota() == nota.getIdNota()){
				return(false);
			}
		}
		this.listaNotas.add(nota);
		this.proximoId++;
		this.salvarArmazenamento();
		return(true);
	}
	
	/**
	 * Método para remover nota da lista. 
	 * Após remover o método "salvarArmazenamento" é chamado
	 * @param idNota
	 * @return true se o aluno foi encontrado na lista para ser removido ou false se ele não foi encontrado.
	 */
	public boolean removerNota(int idNota){
		Iterator<Nota> i = listaNotas.iterator();
		Nota notaComparacao;
		boolean resultado;
		while(i.hasNext()){
			notaComparacao = (Nota) i.next();
			if (notaComparacao.getIdNota() == idNota){
				resultado = this.listaNotas.remove(notaComparacao);
				this.salvarArmazenamento();
				return(resultado);
			}
		}
		return(false);
	}
	
	/**
	 * Método para verificar a existência de uma nota lançada para um aluno em uma atividade
	 * @param idAluno
	 * @param idAtividade
	 * @return Código da nota ou -1 que uma flag que indica a inexistência de tal nota.
	 */
	public int verificarLancamento(int idAluno, int idAtividade){
		Iterator<Nota> i = listaNotas.iterator();
		Nota nota;
		while(i.hasNext()){
			nota = (Nota) i.next();
			if ((nota.getAluno().getIdAluno()==idAluno)&&(nota.getAtividade().getIdAtividade()==idAtividade)){
				return(nota.getIdNota());
			}
		}
		return(-1);
	}
	
	/**
	 * Pesquisa de Notas passando o id da Nota
	 * @param idNota
	 * @return Nota cujo id é igual ao id passado, ou null se nada for encontrado
	 */
	public Nota procurarPorId(int idNota){
		Iterator<Nota> i = listaNotas.iterator();
		Nota nota;
		while(i.hasNext()){
			nota = (Nota) i.next();
			if (nota.getIdNota()==idNota){
				return(nota);
			}
		}
		return(null);
	}
	
	/**
	 * Método para buscar as Notas que está relcionada com alunos
	 * @param idAluno
	 * @return Aluno
	 */
	private Aluno buscarAluno(int idAluno){
		AlunoDaoImplArquivo alunoDaoImplArquivo = new AlunoDaoImplArquivo(idAluno);
		return(alunoDaoImplArquivo.buscarArmazenamentoProcurarPorId(idAluno));
	}
	
	/**
	 * Método para buscar as Notas que está relacionada com atividades
	 * @param idAtividade
	 * @return Lista de Históricos
	 */
	private Atividade buscarAtividade(int idAtividade){
		AtividadeDaoImplArquivo atividadeDaoImplArquivo = new AtividadeDaoImplArquivo(idAtividade);
		return(atividadeDaoImplArquivo.buscarArmazenamentoPorId(idAtividade));
	}
	
}
